#include "activation.h"
#include "activation_thread_kms.h"
#include "activation_udp.h"
#include <QApplication>
#include <QTextCodec>
#include <QTranslator>
#include <QDesktopWidget>
#include <QLocale>
#include <QMessageBox>
#include <QFile>
#include <stdio.h>
#include <stdlib.h>
#include <QFont>
#include <QDesktopWidget>
#include "systemactivationmainwindow.h"
#include "kmsinstallactivationthread.h"
#include "qtsingleapplication/qtsingleapplication.h"
#include "socketmanager.h"

#define PROGRAM_NAME "kylin-activation-ui"
#define LOG_NAME "/.log/kylin-activation/kylin-activation-ui.log"

static FILE *fp_log = NULL;
QString toDir;

void msgHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg)
{
    static char logPath[255] = {0};
    static int uid = -1;
    static int pid = 0;

    Q_UNUSED(context);

    QDateTime currentTime = QDateTime::currentDateTime();
    QString timeStr = currentTime.toString("yy.MM.dd hh:mm:ss +zzz");
    pid = (int)getpid();
    // 获取用于控制命令行输出的环境变量
    char *ctrlEnv = getenv("ACTIVATION_DEBUG");
    QString env;

    // 格式化输出字符串，添加消息发生时间、消息等级
    QString outMsg, outMsg_std;
    outMsg_std = QString("%1").arg(msg);
    switch (type) {
    case QtDebugMsg:
        outMsg = QString("[%1 D .%2]: %3").arg(timeStr).arg(pid).arg(msg);
        break;
    case QtInfoMsg:
        outMsg = QString("[%1 I .%2]: %3").arg(timeStr).arg(pid).arg(msg);
        break;
    case QtWarningMsg:
        outMsg = QString("[%1 W .%2]: %3").arg(timeStr).arg(pid).arg(msg);
        break;
    case QtCriticalMsg:
        outMsg = QString("[%1 C .%2]: %3").arg(timeStr).arg(pid).arg(msg);
        break;
    case QtFatalMsg:
        outMsg = QString("[%1 F .%2]: %3").arg(timeStr).arg(pid).arg(msg);
    }

    if (fp_log != NULL) {
        // 日志文件存在，则输出到日志文件中
        fprintf(fp_log, "%s\n", outMsg.toUtf8().data());
        fflush(fp_log);
    }

//    if (ctrlEnv != NULL) {
//        // 环境变量为true或者1，则将信息输出到命令行
//        env = QString(ctrlEnv).toLower();
//        if ((env == "true") || (env == "1")) {
//            fprintf(stdout, "%s\n", outMsg.toStdString().c_str());
//            fflush(stdout);
//        }
//    }
    fprintf(stdout, "%s\n", outMsg_std.toStdString().c_str());

    // 遇到致命错误，需要终止程序（这里终止程序是可选的）
    if (type == QtFatalMsg)
        abort();
}

void log_env_init(){
    static int uid = -1;
    static char logPath[98] = {0};
    bool _is_root = false;
    toDir = QDir::homePath();
    toDir += "/.log/kylin-activation/";
    QDir dir(toDir);
    if(!dir.exists()) {
        dir.mkdir(toDir);
    }

    QDir dir_conf(QDir::homePath()+"/.config/kylin-activation/");
    if(!dir_conf.exists()) {
        dir_conf.mkdir(QDir::homePath()+"/.config/kylin-activation/");
    }

    // 初始执行时，设置log文件路径
    if (uid == -1) {
        uid = getuid();
    }
    if (uid == 0) {
        // root user
        sprintf(logPath, "/var/log/kylin-activation/kylin-activation-ui.log");
        _is_root = true;
    } else {
        // normal user
        std::string str = QDir::homePath().toStdString();
        const char* ch = str.c_str();
        sprintf(logPath, "%s%s", ch, LOG_NAME);
    }

    if (access(logPath, F_OK|W_OK) == 0) { // log文件存在且可写
        if (fp_log == NULL)
            fp_log = fopen(logPath, "a+");
        QFileInfo info(logPath);
        if (info.size() > 1024*1024*200) { //200MB
            fclose(fp_log); fp_log = NULL;
            QFile fileclean(logPath);
            fileclean.open(QIODevice::WriteOnly | QIODevice::Text | QFile::Truncate);
            fileclean.close();
            if (fp_log == NULL)
                fp_log = fopen(logPath, "a+");
        }
    } else if (access(logPath, F_OK) != 0){ //文件不存在
        if (fp_log == NULL) {
            if (_is_root) { //root用户日志文件
                QDir* dir = new QDir();
                if(!dir->exists("/var/log/kylin-activation/")){
                    dir->mkpath("/var/log/kylin-activation/");
                }
                fp_log = fopen(logPath, "a+");
                if (fp_log == NULL)
                    printf("Can't open logfile!\n");
            } else {
                fp_log = fopen(logPath, "a+");
                if (fp_log == NULL)
                    printf("Can't open logfile!\n");
            }
        }
    } else {
        // log文件不可写，则需要判断是否被打开过，被打开过就需要关闭
        if (fp_log != NULL)
            fclose(fp_log);
        fp_log = NULL;
    }
}

//main函数
int main(int argc, char* argv[])
{
    qunsetenv("SESSION_MANAGER");
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
    QtSingleApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QtSingleApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);

    QString id = QString("kylin-activation" + QLatin1String(getenv("DISPLAY")));
    QtSingleApplication a(id, argc, argv);

    QTranslator translator,translator2;
    QString locale = QLocale::system().name();
    translator.load(QString(":/qmfile/translation/kylin_activation_%1.qm").arg(locale));
    translator2.load(QString("/usr/share/qt5/translations/qt_%1.qm").arg(locale));
    a.installTranslator(&translator);
    a.installTranslator(&translator2);

    log_env_init();
    qInstallMessageHandler(msgHandler);

    if(argc==1 && a.isRunning()) { //界面单例
        qDebug()<<"Activation is running: "<<id;
        a.sendMessage("Activation is running.");
        return EXIT_SUCCESS;
    }

    QLockFile auto_lock(QDir::homePath()+"/.config/kylin-activation/activation-auto.lock");
    if(argc > 1 && strcmp(argv[1],"-auto") == 0) { //单例锁
        if (!auto_lock.tryLock(0)) {
            long long int pid;
            QString hostname, appname;
            auto_lock.getLockInfo(&pid,&hostname,&appname);
            printf("Activation auto is running, Kill [%d] to run the new process.\n",pid);
            exit(0);
        }
    }

    SystemActivationMainWindow w(argc,argv[1]);
    activation_thread_kms *kms_activation = new activation_thread_kms();
    if(argc==1 || (argc>1 && strcmp(argv[1],"-auto")==0))
        w.m_kmsActivation->start();

    a.setActivationWindow(&w);
    QObject::connect(&a, SIGNAL(messageReceived(const QString&)), &w, SLOT(slotMessageReceived(const QString&)));

    //通过/proc/cmdline判断是否处于livecd模式
    FILE *fp;
    char result_buf[2048];
    QString check;
    bool livecd_flag = false;
    fp = popen("cat /proc/cmdline","r");
    if(fp == NULL) {
        printf("cant open /proc/cmdline !");
    } else {
        while(fgets(result_buf, sizeof(result_buf), fp) != NULL && livecd_flag == false) {
            check = QString(result_buf);
            livecd_flag = check.contains("casper");
        }
    }

    if(argc > 1 && strcmp(argv[1],"-auto") == 0) {
        if(livecd_flag) {//处于livecd模式，不提供激活
            qApp->exit(0);
            exit(0);
        } else {
            kms_activation->oemActivate();
            kms_activation->init_udpinfo();
        }
    } else if(argc > 1 && strcmp(argv[1],"-install")==0) {
        qDebug()<<"kms install activation!";
        KmsInstallActivationThread *kmsInstallActivation=new KmsInstallActivationThread;
        kmsInstallActivation->init_udpinfo();
        kmsInstallActivation->timer->start(4000);
    } else {
        if(livecd_flag) { //处于livecd模式，不提供激活
            QMessageBox::about(NULL, QObject::tr("Tips"), QObject::tr("It is currently in livecd mode, please activate it after installing the system!"));
            qApp->exit(0);
            exit(0);
        } else {
            QRect rect=QApplication::desktop()->screenGeometry();
            w.move(rect.center()-w.rect().center());
            w.raise();
            w.showNormal();
            w.activateWindow();
            w.checkAuthorizationFile();
        }
    }
    int ret=a.exec();
    return ret;
}
